# ---------- 简介 ---------- #
# 文件名: CUSketch.py
# 签名：赵宗义，xinshengzzy@foxmail.com, 2021.01.16
# ++++++++++++++++++++ #
from simulators.BaseSimulator import BaseSimulator
import mytools
import my_constants as mc
import 文件工具箱
import heapq


class CUSketch(BaseSimulator):
    def __init__(self, 内存=1.0):
        super(CUSketch, self).__init__()
        tmp = int(0.5*内存*1024.0*1024.0/(4*4))  # 假设这个sketch共有四行
        self.表长1 = tmp
        self.表长2 = tmp
        self.表长3 = tmp
        self.表长4 = tmp
        self.哈希表 = [0]*(self.表长1 + self.表长2 + self.表长3 + self.表长4)
        self.容量 = int(0.25*内存*1024.0*1024.0/17)
        self.流记录集 = dict()
        self.小顶堆 = []

    def 创建数据结构(self):
        self.哈希表 = [0]*(self.表长1 + self.表长2 + self.表长3 + self.表长4)

    def 配置内存方案(self, 内存方案):
        mc.配置内存方案(内存方案)

    def 处理数据包(self, 标识符, 时间戳):
        '''处理一个新到达的数据包'''
        偏移量 = [0]
        for 表长 in [self.表长1, self.表长2, self.表长3]:
            偏移量.append(偏移量[-1] + 表长)
        索引1 = mytools.hash1(标识符.encode('utf-8')) % self.表长1 + 偏移量[0]
        索引2 = mytools.hash2(标识符.encode('utf-8')) % self.表长2 + 偏移量[1]
        索引3 = mytools.hash3(标识符.encode('utf-8')) % self.表长3 + 偏移量[2]
        索引4 = mytools.hash4(标识符.encode('utf-8')) % self.表长4 + 偏移量[3]
        流长度 = -1
        for 索引 in [索引1, 索引2, 索引3, 索引4]:
            if -1 == 流长度 or self.哈希表[索引] < 流长度:
                流长度 = self.哈希表[索引]
        流长度 += 1
        for 索引 in [索引1, 索引2, 索引3, 索引4]:
            if 流长度 > self.哈希表[索引]:
                self.哈希表[索引] = 流长度
        if 标识符 in self.流记录集:
            self.流记录集[标识符] += 1
        elif len(self.流记录集) < self.容量:
            self.流记录集[标识符] = 流长度
            heapq.heappush(self.小顶堆, (流长度, 标识符))
        else:  # 我们要考虑替换流记录集中的数据流了
            self.更新流记录集(标识符, 流长度)

    def 更新流记录集(self, 标识符, 流长度):
        while True:
            临流长度, 临标识符 = heapq.heappop(self.小顶堆)
            assert(临流长度 <= self.流记录集[临标识符])
            if 临流长度 < self.流记录集[临标识符]:
                heapq.heappush(self.小顶堆, (self.流记录集[临标识符], 临标识符))
            else:  # 临流长度 == self.流记录集[临标识符]
                if 临流长度 >= 流长度:
                    heapq.heappush(self.小顶堆, (self.流记录集[临标识符], 临标识符))
                    break
                else:
                    del self.流记录集[临标识符]
                    self.流记录集[标识符] = 流长度
                    heapq.heappush(self.小顶堆, (流长度, 标识符))
                    break

    def 备份(self, 文件名):
        备份 = dict()
        备份["流记录集"] = self.流记录集
        文件工具箱.备份数据结构(备份, 文件名)
